package cn.xmkeshe.utils;

import cn.xmkeshe.back.ILoggerServiceBack;
import cn.xmkeshe.model.Logger;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.sql.Timestamp;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@Component
@Aspect
public class RequestLogAspect {
    private final static org.slf4j.Logger LOGGER = LoggerFactory.getLogger(RequestLogAspect.class);

    Logger log = new Logger();

    @Resource
    private ILoggerServiceBack iLogServiceBack;

    @Pointcut("execution(* cn.xmkeshe.controller..*(..))")
    public void requestServer() {
    }

    @Before("requestServer()")
    public void doBefore(JoinPoint joinPoint) {
      ServletRequestAttributes attributes = (ServletRequestAttributes)
              RequestContextHolder.getRequestAttributes();
      HttpServletRequest request = attributes.getRequest();

      String ip = request.getRemoteAddr();
      String url = request.getRequestURL().toString();
      String httpMethod = request.getMethod();
      String typeName = joinPoint.getSignature().getDeclaringTypeName();
      String name = joinPoint.getSignature().getName();
      String classMethod = typeName + name;
      log.setIp(ip);
      log.setUrl(url);
      log.setHttpMethod(httpMethod);
      log.setClassMethod(classMethod);
//      LOGGER.info("===============================Start========================");
//      LOGGER.info("IP                 : {}", ip );
//      LOGGER.info("URL                : {}", url);
//      LOGGER.info("HTTP Method        : {}", httpMethod);
//      LOGGER.info("Class Method       : {}.{}", typeName, name);
    }


    @Around("requestServer()")
    public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
      long start = System.currentTimeMillis();
      Object Result = proceedingJoinPoint.proceed();
      String requestParams = getRequestParams(proceedingJoinPoint).toString();
      String result = Result.toString();
      long timeCost = System.currentTimeMillis() - start;
//      System.out.println(log);
      log.setRequestParams(requestParams);
      log.setResult(result);
      log.setTimeCost(timeCost);

//      LOGGER.info("Request Params     : {}", requestParams);
//      LOGGER.info("Result               : {}", result);
//      LOGGER.info("Time Cost            : {} ms", timeCost);

      return Result;
    }

    @After("requestServer()")
    public void doAfter(JoinPoint joinPoint) {
//      LOGGER.info("===============================End========================");
      try{
        String targetName = joinPoint.getTarget().getClass().getName();
        String methodName = joinPoint.getSignature().getName();
        Object[] arguments = joinPoint.getArgs();
        Class targetClass = Class.forName(targetName);
        Method[] methods = targetClass.getMethods();
        String operationName = "";
        String operationType = "";
        for(Method method : methods){
          if(method.getName().equals(methodName)){
            Class[] classes = method.getParameterTypes();
            if(classes.length == arguments.length){
              operationName = method.getAnnotation(cn.xmkeshe.utils.Log.class).operationName();
              operationType = method.getAnnotation(cn.xmkeshe.utils.Log.class).operationType();
            }
          }
        }
        log.setDescription(operationName);
        log.setType(operationType);
        log.setCreateDate(new Timestamp(new Date().getTime()));
//        System.out.println("可以不"+operationName);

      }catch (Exception e){
        e.printStackTrace();
      }
      iLogServiceBack.insert(log);
    }

    /**
     * 获取入参
     * @param proceedingJoinPoint
     *
     * @return
     * */
    private Map<String, Object> getRequestParams(ProceedingJoinPoint proceedingJoinPoint) {
      Map<String, Object> requestParams = new HashMap<>();

      //参数名
      String[] paramNames =
              ((MethodSignature)proceedingJoinPoint.getSignature()).getParameterNames();
      //参数值
      Object[] paramValues = proceedingJoinPoint.getArgs();

      for (int i = 0; i < paramNames.length; i++) {
        Object value = paramValues[i];
        requestParams.put(paramNames[i], value);
      }

      return requestParams;
    }
  }
